﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using MiniStock.Entities.Common;

namespace MiniStock.Infrastructure.EFExtensions
{
    public static class MappingExtender
    {
        public static List<T> MapResults<T>(this IDbCommand cmd)
             where T : new()
        {
            var result = new List<T>();
            var maps = new List<Expression<Action<T, object>>>();

            cmd.Connection.Open();
            using (var reader = cmd.ExecuteReader())
            {
                var table = reader.GetSchemaTable();

                while (reader.Read())
                {
                    T item = new T();

                    for (int i = 0; i < table.Rows.Count; i++)
                    {
                        SetValue(item, (string)table.Rows[i]["ColumnName"], reader.GetValue(i));
                    }

                    result.Add(item);
                }
            }
            return result;

        }

        private static void SetValue(object item, string name, object value)
        {
            if (item == null)
                throw new ApplicationException("Cannot bind value to " + name + ", target object is null");

            var t = item.GetType();
            if (value == DBNull.Value)
                value = null;

            var pi = t.GetProperty(name);
            if (pi != null)
            {
                pi.SetValue(item, value, null);
            }
            else
            {
                var parts = name.Split(new[]
                                               {
                                                   '_'
                                               }, 2);

                pi = t.GetProperty(parts[0]);

                if (pi == null)
                    throw new ApplicationException("Cannot bind value to " + name + ", property not found");

                var o = pi.GetValue(item, null);
                if (o == null)
                {
                    var ci = pi.PropertyType.GetConstructor(new Type[] {});
                    o = ci.Invoke(null);
                    pi.SetValue(item, o, null);
                }

                SetValue(o, parts[1], value);
            }
        }
    }

}
